package com.yuelao.yuelao_backend.filter;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import java.io.IOException;
import java.util.UUID;

/**
 * 请求日志过滤器
 * 记录每个HTTP请求的详细信息，包括URL、方法、IP、耗时、响应状态等
 */
@Component
@Slf4j
public class RequestLoggingFilter extends OncePerRequestFilter {

    private static final String REQUEST_ID_HEADER = "X-Request-Id";

    @Override
    protected void doFilterInternal(@NonNull HttpServletRequest request,
                                    @NonNull HttpServletResponse response,
                                    @NonNull FilterChain filterChain)
            throws ServletException, IOException {

        // 生成请求ID用于追踪
        String requestId = request.getHeader(REQUEST_ID_HEADER);
        if (!StringUtils.hasText(requestId)) {
            requestId = UUID.randomUUID().toString().replace("-", "").substring(0, 16);
        }
        response.setHeader(REQUEST_ID_HEADER, requestId);

        // 包装请求和响应以便读取内容
        ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
        ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(response);

        long startTime = System.currentTimeMillis();

        try {
            // 记录请求开始
            logRequest(wrappedRequest, requestId);

            // 继续过滤链
            filterChain.doFilter(wrappedRequest, wrappedResponse);

        } finally {
            long duration = System.currentTimeMillis() - startTime;

            // 记录请求结束
            logResponse(wrappedRequest, wrappedResponse, requestId, duration);

            // 将响应内容写回
            wrappedResponse.copyBodyToResponse();
        }
    }

    /**
     * 记录请求信息
     */
    private void logRequest(HttpServletRequest request, String requestId) {
        String method = request.getMethod();
        String uri = request.getRequestURI();
        String queryString = request.getQueryString();
        String clientIp = getClientIp(request);
        String userAgent = request.getHeader("User-Agent");
        String contentType = request.getContentType();

        StringBuilder logMessage = new StringBuilder();
        logMessage.append("\n========== Request Start ==========\n");
        logMessage.append(String.format("Request ID: %s\n", requestId));
        logMessage.append(String.format("Method: %s\n", method));
        logMessage.append(String.format("URI: %s\n", uri));
        if (StringUtils.hasText(queryString)) {
            logMessage.append(String.format("Query: %s\n", queryString));
        }
        logMessage.append(String.format("Client IP: %s\n", clientIp));
        if (StringUtils.hasText(userAgent)) {
            logMessage.append(String.format("User-Agent: %s\n", userAgent));
        }
        if (StringUtils.hasText(contentType)) {
            logMessage.append(String.format("Content-Type: %s\n", contentType));
        }

        log.info(logMessage.toString());
    }

    /**
     * 记录响应信息
     */
    private void logResponse(HttpServletRequest request, ContentCachingResponseWrapper response,
                             String requestId, long duration) {
        int status = response.getStatus();
        String method = request.getMethod();
        String uri = request.getRequestURI();

        StringBuilder logMessage = new StringBuilder();
        logMessage.append(String.format("Request ID: %s | %s %s | Status: %d | Duration: %dms",
                requestId, method, uri, status, duration));
        logMessage.append("\n========== Request End ==========");

        // 根据响应状态选择日志级别
        if (status >= 500) {
            log.error(logMessage.toString());
        } else if (status >= 400) {
            log.warn(logMessage.toString());
        } else {
            log.info(logMessage.toString());
        }
    }

    /**
     * 获取客户端真实IP地址
     * 支持代理服务器场景
     */
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (!StringUtils.hasText(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (!StringUtils.hasText(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (!StringUtils.hasText(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (!StringUtils.hasText(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (!StringUtils.hasText(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (!StringUtils.hasText(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        // 多个代理时，第一个IP为客户端真实IP
        if (StringUtils.hasText(ip) && ip.contains(",")) {
            ip = ip.split(",")[0].trim();
        }

        return ip;
    }

    /**
     * 排除静态资源和健康检查等路径
     */
    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) {
        String path = request.getRequestURI();
        return path.startsWith("/actuator") ||
               path.startsWith("/favicon.ico") ||
               path.endsWith(".css") ||
               path.endsWith(".js") ||
               path.endsWith(".png") ||
               path.endsWith(".jpg") ||
               path.endsWith(".gif") ||
               path.endsWith(".ico");
    }
}
